/*
 * Copyright (c) 1993-2003, Silicon Graphics, Inc.
 * All Rights Reserved
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose and without fee is hereby granted, provided that the above
 * copyright notice appear in all copies and that both the copyright
 * notice and this permission notice appear in supporting documentation,
 * and that the name of Silicon Graphics, Inc. not be used in
 * advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission.
 *
 * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" AND
 * WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
 * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
 * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
 * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
 * OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION, LOSS OF
 * PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF THIRD
 * PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN ADVISED OF
 * THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE POSSESSION, USE
 * OR PERFORMANCE OF THIS SOFTWARE.
 *
 * US Government Users Restricted Rights 
 * Use, duplication, or disclosure by the Government is subject to
 * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
 * (c)(1)(ii) of the Rights in Technical Data and Computer Software
 * clause at DFARS 252.227-7013 and/or in similar or successor clauses
 * in the FAR or the DOD or NASA FAR Supplement.  Unpublished - rights
 * reserved under the copyright laws of the United States.
 *
 * Contractor/manufacturer is:
 *	Silicon Graphics, Inc.
 *	1500 Crittenden Lane
 *	Mountain View, CA  94043
 *	United State of America
 *
 * OpenGL(R) is a registered trademark of Silicon Graphics, Inc.
 */

/*
 *  lines.c
 *  This program demonstrates geometric primitives and
 *  their attributes.
 */
#import "glm.h"

#define  BUFFER_OFFSET(bytes) ((GLubyte*)NULL+(bytes))
#define  NumberOfArray(array) (sizeof(array)/sizeof(array[0]))

typedef struct {
    GLfloat x,y,z;
} vec3;

typedef struct {
    vec3 xlate;
    GLfloat angle;
    vec3 axis;
} XForm;

enum {Cube,Cone,NumVAOs};
GLuint VAO[NumVAOs];
GLenum PrimeType[NumVAOs];
GLsizei NumElements[NumVAOs];

XForm Xform[NumVAOs] = {
    {{-2.0,0.0,0.0},30.0,{1.0,-1.0,-1.0}},
    {{0.0,0.0,0.0},30.0,{1.0,0.0,0.0}}
};

GLfloat Angle = 0.0;

void init(void) 
{
    glClearColor (0.0, 0.0, 0.0, 0.0);
    glShadeModel (GL_FLAT);
    
    enum {Vetices,Colors,Elements,NumVBOs};
    GLuint buffers[NumVBOs];
    glGenVertexArraysAPPLE(NumVAOs, VAO);
    
    {
        GLfloat vertices[][3] = {
            { -0.5, -0.5, -0.5 },
            { -0.5, -0.5, 0.5 },
            { -0.5, 0.5, 0.5 },
            { -0.5, 0.5, -0.5 },
            { 0.5, -0.5, -0.5 },
            { 0.5, -0.5, 0.5 },
            { 0.5, 0.5, 0.5 },
            { 0.5, 0.5, -0.5 }
        };
        
        GLfloat colors[][3] = {
            { 0.0, 0.0, 0.0 },
            { 0.0, 0.0, 1.0 },
            { 0.0, 1.0, 0.0 },
            { 0.0, 1.0, 1.0 },
            { 1.0, 0.0, 0.0 },
            { 1.0, 0.0, 1.0 },
            { 1.0, 1.0, 0.0 },
            { 1.0, 1.0, 1.0 }
        };
        
        GLubyte indices[][4] = {
            { 4, 5, 6, 7 },
            { 1, 2, 6, 5 },
            { 0, 1, 5, 4 },
            { 0, 3, 2, 1 },
            { 0, 4, 7, 3 },
            { 2, 3, 7, 6 }
        };  
        glBindVertexArrayAPPLE(VAO[Cube]);
        glGenBuffers(NumVBOs, buffers);
        glBindBuffer(GL_ARRAY_BUFFER, buffers[Vetices]);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
        glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));
        glEnableClientState(GL_VERTEX_ARRAY);
        
        glBindBuffer(GL_ARRAY_BUFFER, buffers[Colors]);
        glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
        glColorPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));
        glEnableClientState(GL_COLOR_ARRAY);
                
        
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[Elements]);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
        
        PrimeType[Cube] = GL_QUADS;
        NumElements[Cube] = sizeof(indices);        
    }
    
    {
        int idx;
        float dTheta;
#define  NumConePoints 36
        
        GLfloat coneVerts[NumConePoints+1][3] = {
            {0.0,0.0,1.0}
        };
        GLfloat coneColors[NumConePoints+1][3] = {
            {1.0,1.0,1.0}
        };
        GLubyte coneIndices[NumConePoints+1];
        coneIndices[0] = 0;
        dTheta = 2*M_PI/(NumConePoints-1);
        idx = 1;
        for (int i=0; i<NumConePoints; i++,idx++) {
            float theta = i *dTheta;
            coneVerts[idx][0] = cos(theta);
            coneVerts[idx][1] = sin(theta);
            coneVerts[idx][2] = 0.0;
            
            coneColors[idx][0] = cos(theta);
            coneColors[idx][1] = sin(theta);
            coneColors[idx][2] = 1.0;
            
            coneIndices[idx] = idx;
        }
        
        glBindVertexArrayAPPLE(VAO[Cone]);
        glGenBuffers(NumVBOs, buffers);
        glBindBuffer(GL_ARRAY_BUFFER, buffers[Vetices]);
        glBufferData(GL_ARRAY_BUFFER, sizeof(coneVerts), coneVerts, GL_STATIC_DRAW);
        glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));
        glEnableClientState(GL_VERTEX_ARRAY);
        
        glBindBuffer(GL_ARRAY_BUFFER, buffers[Colors]);
        glBufferData(GL_ARRAY_BUFFER, sizeof(coneColors), coneColors, GL_STATIC_DRAW);
        glColorPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));
        glEnableClientState(GL_COLOR_ARRAY);
        
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[Elements]);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(coneIndices), coneIndices, GL_STATIC_DRAW);

        PrimeType[Cone] = GL_TRIANGLE_FAN;
        NumElements[Cone] = sizeof(coneIndices);
    }
    glEnable(GL_DEPTH_TEST);
}

void display(void)
{    
    glClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glPushMatrix();
    glRotatef(Angle, 0.0, 1.0, 0.0);
    
    for (int i=0; i<NumVAOs; ++i) {
        glPushMatrix();
        glTranslatef(Xform[i].xlate.x, Xform[i].xlate.y, Xform[i].xlate.z);
        glRotatef(Xform[i].angle, Xform[i].axis.x, Xform[i].axis.y, Xform[i].axis.z);
        glBindVertexArrayAPPLE(VAO[i]);
        glDrawElements(PrimeType[i], NumElements[i], GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
        glPopMatrix();
    }
    glPopMatrix();
    glutSwapBuffers();
}

void reshape (int w, int h)
{
    glViewport (0, 0, (GLsizei) w, (GLsizei) h);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    gluOrtho2D (-4, 4, -4, 4);
}

void keyboard(unsigned char key, int x, int y)
{
    switch (key) {
        case 27:
            exit(0);
            break;
    }
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize (500, 500); 
    glutInitWindowPosition (100, 100);
    glutCreateWindow ("vao");
    init ();
    glutDisplayFunc(display); 
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyboard);
    glutMainLoop();
    return 0;
}
